package com.fw.ui.core.authentication;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;

import com.fw.service.bean.ErrorBean;
import com.fw.service.bouserauthentication.bean.BOUserAuthenticationBean;
import com.fw.ui.bao.AuthenticationBAO;
import com.fw.ui.bean.AuthenticationBean;
import com.fw.ui.util.VaadinApplicationObjectSupport;
import com.vaadin.server.VaadinServletService;

@Component
public class AuthenticationProvider implements org.springframework.security.authentication.AuthenticationProvider, Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    @Autowired
    protected transient VaadinApplicationObjectSupport app;
    @Autowired
    private AuthenticationBAO authenticationBAO;

    @SuppressWarnings("unchecked")
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
	String loginType = app.getMessage("APPLICATION.LOGIN.TYPE");

	Object principalObj = authentication.getPrincipal();
	Object credentialObj = authentication.getCredentials();

	AuthenticationUserToken authenticationUserToken = new AuthenticationUserToken(principalObj, credentialObj);
	try {
	    Map<String, Serializable> mapResult = null;
	    if (principalObj == null || credentialObj == null) {
		AuthenticationServiceException authenticationException = new AuthenticationServiceException(
			"com.fw.ui.view.common.LoginPanel.message.failed.invalid");
		throw authenticationException;
	    }
	    if (AuthenticationBAO.AUTHENTICATION_BO_TYPE.equals(loginType)) {
		mapResult = authenticationBAO.authenticateBOUser(principalObj.toString(), credentialObj.toString(), VaadinServletService
			.getCurrentRequest().getRemoteAddr());
	    } else if (AuthenticationBAO.AUTHENTICATION_MC_TYPE.equals(loginType)) {

	    }

	    if (mapResult != null) {
		List<ErrorBean> errorBeans = (List<ErrorBean>) mapResult.get(List.class.getName() + "." + ErrorBean.class.getName());
		BOUserAuthenticationBean boUserAuthenticationBean = (BOUserAuthenticationBean) mapResult.get(BOUserAuthenticationBean.class
			.getName());

		if (boUserAuthenticationBean != null) {
		    AuthenticationBean authenticationBean = new AuthenticationBean(boUserAuthenticationBean);
		    authenticationUserToken.setAuthenticationBean(authenticationBean);
		}

		if (errorBeans != null && !errorBeans.isEmpty()) {
		    String messageCode = "";
		    for (ErrorBean errorBean : errorBeans) {
			messageCode += errorBean.getErrorCode();
			if (errorBean.getErrorParameters() != null && errorBean.getErrorParameters().length > 0) {
			    messageCode += "{";
			    for (String parameter : errorBean.getErrorParameters()) {
				messageCode += parameter + ",";
			    }
			    messageCode += "}";
			}
		    }
		    authenticationUserToken.setAuthenticated(false);
		    authenticationUserToken.setMessageCode(messageCode);

		} else if (boUserAuthenticationBean != null) {
		    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
		    authorities.add(new SimpleGrantedAuthority("ROLE_BASE"));
		    authenticationUserToken.setAuthorities(authorities);
		    authenticationUserToken.setAuthenticated(true);
		    AuthenticationBean authenticationBean = new AuthenticationBean(boUserAuthenticationBean);
		    authenticationUserToken.setAuthenticationBean(authenticationBean);
		}
	    }
	} catch (AuthenticationException e) {
	    AuthenticationServiceException authenticationException = new AuthenticationServiceException(e.getMessage());
	    throw authenticationException;
	} catch (Exception e) {
	    e.printStackTrace();
	    AuthenticationServiceException authenticationException = new AuthenticationServiceException(e.getMessage());
	    throw authenticationException;
	}

	return authenticationUserToken;
    }

    @Override
    public boolean supports(Class<?> authentication) {
	return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
    }

}
